home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 21 / CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso / CUCD / Programming / Python-1.4 / Python1.4_Source / Modules / amigamodule.c next >
C/C++ Source or Header  |  1998-01-31  |  28KB  |  1,343 lines

  1. /**************************************************************\
  2. **                                                            **
  3. **  AMIGA module implementation, for SAS/C version 6.58       **
  4. **                                                            **
  5. **  Made by Irmen de Jong (ijong@gak.nl)                      **
  6. **                                                            **
  7. **  27-mar-96: Added a lot of AmiTCP functions!               **
  8. **   2-apr-96: Many small fixes & enhancements.               **
  9. **  11-apr-96: Totally rewritten the environment handling.    **
  10. **             Now creates 4 separate dictionaries.           **
  11. **             Fixed link(), added symlink() and readlink().  **
  12. **  29-may-96: Added filenote() and fullpath()                **
  13. **  11-jun-96: Moved filenote() to doslib/SetComment          **
  14. **  12-jun-96: Removed execv                                  **
  15. **  29-Aug-96: fixed getcwd(), some minor errno fixes         **
  16. **  26-Dec-96: upgraded to 1.4: added putenv(), remove()      **
  17. **             fixed mkdir: default protbits (0777)           **
  18. **   6-Apr-97: fixed bug in readlink (lock was incorrect)     **
  19. **   6-Nov-97: added uname()                                  **
  20. **                                                            **
  21. **  Adapted from posixmodule.c; implements as much of the     **
  22. **  functionality of this module as possible.                 **
  23. **                                                            **
  24. **                                                            **
  25. **  TO DO: Implement execv(e) and threads (if possible).      **
  26. **                                                            **
  27. **  NOTE: Don't forget __io2errno conversion!!!!!!!!!!!!!!!!  **
  28. **                                                            **
  29. \**************************************************************/
  30.  
  31.  
  32. #include "allobjects.h"
  33. #include "modsupport.h"
  34. #include "ceval.h"
  35. #include "sysmodule.h"
  36. #include "osdefs.h"
  37.  
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <errno.h>
  41. #include <fcntl.h>
  42. #include <unistd.h>
  43. #include <stat.h>
  44. #include <dos.h>
  45. #include <sys/types.h>
  46. #include <proto/dos.h>
  47. #include <proto/exec.h>
  48. #include <dos/dosextens.h>
  49. #include <dos/var.h>
  50. #include <dos/dostags.h>
  51. #include <exec/execbase.h>
  52.  
  53. #include "mytime.h"     /* For clock_t on some systems */
  54.  
  55. #ifdef HAVE_UTIME_H
  56. #include <utime.h>
  57. #endif
  58.  
  59. #include <dirent.h>
  60. #define NAMLEN(dirent) strlen((dirent)->d_name)
  61.  
  62. #ifdef AMITCP
  63. #include <clib/netlib_protos.h>
  64. #endif
  65.  
  66. /* defined elsewhere */
  67. extern int setenv(const char *name, const char *value, int overwrite);
  68.  
  69. /* Prototypes for functions defined in modules/amigamodule.c */
  70.  
  71. /***
  72. static int _static_inline_select(int , fd_set * , fd_set * , fd_set * , struct compatible_timeval * );
  73. static unsigned char * _static_inline_inet_ntoa(struct in_addr );
  74. static struct in_addr _static_inline_inet_makeaddr(int , int );
  75. static unsigned long _static_inline_inet_lnaof(struct in_addr );
  76. static unsigned long _static_inline_inet_netof(struct in_addr );
  77. ***/
  78.  
  79.  
  80.  
  81. /* Return a dictionary corresponding to the AmigaDOS environment table. */
  82. /* That is, scan ENV: for global environment variables.                 */
  83. /* The local shell environment variables are put into another table.    */
  84. /* (changed 31-mar-96) */
  85.  
  86. static int
  87. convertenviron(PyObject **glob, PyObject **loc,
  88.                PyObject **both, PyObject **aliases)
  89. {
  90.     BPTR dlok;
  91.     struct FileInfoBlock __aligned fib;
  92.     PyObject *v;
  93.     char buf[200];
  94.     struct LocalVar *lvar;
  95.     struct List *localvars;
  96.  
  97.     *glob=newdictobject();
  98.     *loc=newdictobject();
  99.     *both=newdictobject();
  100.     *aliases=newdictobject();
  101.  
  102.     if(!*glob || !*loc || !*both || !*aliases)
  103.     {
  104.         if(*glob) DECREF(*glob);
  105.         if(*loc) DECREF(*loc);
  106.         if(*both) DECREF(*both);
  107.         if(*aliases) DECREF(*aliases);
  108.         return 0;
  109.     }
  110.  
  111.     /* Read global vars from ENV: */
  112.     /* Put them in 'glob' and in 'both'. */
  113.  
  114.     if(dlok=Lock("ENV:",ACCESS_READ))
  115.     {
  116.         if(Examine(dlok,&fib))
  117.         {
  118.             while(ExNext(dlok,&fib))
  119.             {
  120.                 if(fib.fib_DirEntryType<0)
  121.                 {
  122.                     int len=GetVar(fib.fib_FileName,buf,200,GVF_GLOBAL_ONLY);
  123.                     if(len>=0 && (v=newstringobject(buf)))
  124.                     {
  125.                         dictinsert(*glob,fib.fib_FileName,v);
  126.                         dictinsert(*both,fib.fib_FileName,v);
  127.                         DECREF(v);
  128.                     }
  129.                 }
  130.             }
  131.         }
  132.     }
  133.  
  134.     if(dlok) UnLock(dlok);
  135.  
  136.     /* Scan the local shell environment, including "RC" and "Result2"!   */
  137.     /* Put shell vars in 'loc' and 'both', and aliases in 'aliases'. */
  138.     /* Because of the fact that the inserting of local vars into 'both' */
  139.     /* happens AFTER the insertion of global vars, the formor overwrite */
  140.     /* the latter, and thus have higher priority (as it should be). */
  141.  
  142.     localvars = (struct List*) &((struct Process*)FindTask(0))->pr_LocalVars;
  143.  
  144.     if(!IsListEmpty(localvars))
  145.     {
  146.         lvar = (struct LocalVar*) localvars->lh_Head;
  147.         do {
  148.             strncpy(buf,lvar->lv_Value,lvar->lv_Len);
  149.             buf[lvar->lv_Len]=0;
  150.  
  151.             if(v=newstringobject(buf))
  152.             {
  153.                 if(lvar->lv_Node.ln_Type==LV_VAR)
  154.                 {
  155.                     dictinsert(*loc,lvar->lv_Node.ln_Name,v);
  156.                     dictinsert(*both,lvar->lv_Node.ln_Name,v);
  157.                 }
  158.                 else if(lvar->lv_Node.ln_Type==LV_ALIAS)
  159.                     dictinsert(*aliases,lvar->lv_Node.ln_Name,v);
  160.  
  161.                 DECREF(v);
  162.             }
  163.         } while((lvar=(struct LocalVar*)lvar->lv_Node.ln_Succ)->lv_Node.ln_Succ);
  164.     }
  165.  
  166.  
  167.     return 1;
  168. }
  169.  
  170.  
  171. static object *AmigaError; /* Exception amiga.error */
  172.  
  173. /* Set a Amiga-specific error from errno, and return NULL */
  174.  
  175. static object * amiga_error(void)
  176. {
  177.     return err_errno(AmigaError);
  178. }
  179.  
  180.  
  181. /* AMIGA generic methods */
  182.  
  183. static object *
  184. amiga_1str(object *args, int (*func)(const char *))
  185. {
  186.     char *path1;
  187.     int res;
  188.     if (!getargs(args, "s", &path1))
  189.         return NULL;
  190.     BGN_SAVE
  191.     res = (*func)(path1);
  192.     END_SAVE
  193.     if (res < 0)
  194.         return amiga_error();
  195.     INCREF(None);
  196.     return None;
  197. }
  198.  
  199. static object *
  200. amiga_2str(object *args, int (*func)(const char *, const char *))
  201. {
  202.     char *path1, *path2;
  203.     int res;
  204.     if (!getargs(args, "(ss)", &path1, &path2))
  205.         return NULL;
  206.     BGN_SAVE
  207.     res = (*func)(path1, path2);
  208.     END_SAVE
  209.     if (res < 0)
  210.         return amiga_error();
  211.     INCREF(None);
  212.     return None;
  213. }
  214.  
  215. static object *
  216. amiga_strint(object *args, int (*func)(const char *, int))
  217. {
  218.     char *path;
  219.     int i;
  220.     int res;
  221.     if (!getargs(args, "(si)", &path, &i))
  222.         return NULL;
  223.     BGN_SAVE
  224.     res = (*func)(path, i);
  225.     END_SAVE
  226.     if (res < 0)
  227.         return amiga_error();
  228.     INCREF(None);
  229.     return None;
  230. }
  231.  
  232. static object *
  233. amiga_strintint(object *args, int (*func)(const char *, int, int))
  234. {
  235.     char *path;
  236.     int i,i2;
  237.     int res;
  238.     if (!getargs(args, "(sii)", &path, &i, &i2))
  239.         return NULL;
  240.     BGN_SAVE
  241.     res = (*func)(path, i, i2);
  242.     END_SAVE
  243.     if (res < 0)
  244.         return amiga_error();
  245.     INCREF(None);
  246.     return None;
  247. }
  248.  
  249. static object *
  250. amiga_do_stat(object *self, object *args, int (*statfunc)(const char *, struct stat *))
  251. {
  252.     struct stat st;
  253.     char *path;
  254.     int res;
  255.     if (!getargs(args, "s", &path))
  256.         return NULL;
  257.     BGN_SAVE
  258.     res = (*statfunc)(path, &st);
  259.     END_SAVE
  260.     if (res != 0)
  261.         return amiga_error();
  262.     return mkvalue("(llllllllll)",
  263.             (long)st.st_mode,
  264.             (long)st.st_ino,
  265.             (long)st.st_dev,
  266.             (long)st.st_nlink,
  267.             (long)st.st_uid,
  268.             (long)st.st_gid,
  269.             (long)st.st_size,
  270.             (long)st.st_atime,
  271.             (long)st.st_mtime,
  272.             (long)st.st_ctime);
  273. }
  274.  
  275.  
  276. /* AMIGA methods */
  277.  
  278. static object *
  279. amiga_chdir(object *self, object *args)
  280. {
  281.     return amiga_1str(args, chdir);
  282. }
  283.  
  284. static object *
  285. amiga_chmod(object *self, object *args)
  286. {
  287.     return amiga_strint(args, chmod);
  288. }
  289.  
  290. #ifdef HAVE_CHOWN
  291. static object *
  292. amiga_chown(object *self, object *args)
  293. {
  294.     return amiga_strintint(args, chown);
  295. }
  296. #endif /* HAVE_CHOWN */
  297.  
  298. #ifdef HAVE_GETCWD
  299. static object *
  300. amiga_getcwd(object *self, object *args)
  301. {
  302.     char buf[MAXPATHLEN];
  303.     char *res;
  304.     if (!getnoarg(args))
  305.             return NULL;
  306.     BGN_SAVE
  307.     res = getcwd(buf, sizeof buf);
  308.     END_SAVE
  309.     if (res == NULL)
  310.             return amiga_error();
  311.     return newstringobject(buf);
  312. }
  313. #endif
  314.  
  315. /** Amiga implementation of link(2)  (2-apr-96) **/
  316.  
  317. static BOOL checkIt(char *from, BPTR to, BOOL root)
  318. {
  319.     struct FileInfoBlock __aligned fib;
  320.  
  321.     if(Examine(to,&fib))
  322.     {
  323.         if(fib.fib_EntryType>0)
  324.         {
  325.             // directory! Check some things (loops etc)
  326.             char* pp;
  327.             char p;
  328.             BPTR fromLock,temp;
  329.  
  330.             // only superuser may link directories
  331.             if(!root)
  332.             {
  333.                 errno=EPERM; return FALSE;
  334.             }
  335.  
  336.             pp = PathPart(from);
  337.             p = *pp;
  338.             *pp = 0;
  339.             fromLock=Lock(from,SHARED_LOCK);
  340.             *pp=p;
  341.  
  342.             if(fromLock)
  343.             {
  344.                 do {
  345.                     if(SameLock(fromLock,to)==LOCK_SAME)
  346.                     {
  347.                         UnLock(fromLock);
  348.                         errno = ELOOP;
  349.                         return FALSE;       // link loop
  350.                     }
  351.  
  352.                     temp = fromLock;
  353.                     fromLock = ParentDir(fromLock);
  354.                     UnLock(temp);
  355.                 } while (fromLock);
  356.  
  357.                 return TRUE;       // dir, OK.
  358.             }
  359.             else errno=__io2errno(_OSERR=IoErr());
  360.         }
  361.         else return TRUE;      // file, OK.
  362.     }
  363.     else errno=__io2errno(_OSERR=IoErr());
  364.  
  365.     return FALSE;
  366. }
  367.  
  368. /* LINK: make hardlink from 'from' to 'to' (to must exist, from is new) */
  369. /* 'from' may not be a directory if you are not the super-user. */
  370. /* 0=ok, -1=err */
  371. static int link(const char *to, const char *from)
  372. {
  373.     BOOL root;
  374.     BPTR toLock;
  375.  
  376.     /* are we superuser? */
  377.     if (!checkusergrouplib())
  378.     {
  379.         err_clear();
  380.         root=TRUE;  /* can't tell... so be root */
  381.     }
  382.     else if(getuid()==0) root = TRUE;
  383.     else root=FALSE;
  384.  
  385.     if(toLock=Lock(to,SHARED_LOCK))
  386.     {
  387.         if(checkIt(from,toLock,root))
  388.         {
  389.             if(MakeLink(from,(LONG)toLock,FALSE))
  390.             {
  391.                 UnLock(toLock);
  392.                 return 0;
  393.             }
  394.             else errno=__io2errno(_OSERR=IoErr());
  395.         }
  396.         UnLock(toLock);
  397.     }
  398.     else errno=__io2errno(_OSERR=IoErr());
  399.     
  400.     return -1;
  401. }
  402.  
  403.  
  404. static object *
  405. amiga_link(object *self, object *args)
  406. {
  407.     return amiga_2str(args, link);
  408. }
  409.  
  410. static object *
  411. amiga_listdir(object *self, object *args)
  412. {
  413.     BPTR dlok;
  414.     char *name;
  415.     struct FileInfoBlock __aligned fib;
  416.     PyObject *d;
  417.  
  418.     if (!getargs(args, "s", &name)) return NULL;
  419.  
  420.     if ((d = newlistobject(0)) == NULL) return NULL;
  421.  
  422.     if(dlok=Lock(name,ACCESS_READ))
  423.     {
  424.         if(Examine(dlok,&fib))
  425.         {
  426.             while(ExNext(dlok,&fib))
  427.             {
  428.                 PyObject *v = PyString_FromString(fib.fib_FileName);
  429.                 if(v==NULL)
  430.                 {
  431.                     Py_DECREF(d); d=NULL; break;
  432.                 }
  433.  
  434.                 if(addlistitem(d,v)!=0)
  435.                 {
  436.                     Py_DECREF(v); Py_DECREF(d); d=NULL; break;
  437.                 }
  438.                 Py_DECREF(v);
  439.             }
  440.         }
  441.         UnLock(dlok);
  442.     }
  443.  
  444.     if(IoErr()==ERROR_NO_MORE_ENTRIES) return d;
  445.  
  446.     Py_DECREF(d);
  447.     errno=__io2errno(_OSERR=IoErr());
  448.     return amiga_error();
  449. }
  450.  
  451. /** custom mkdir() implementation **/
  452. /** This version actually sets protection bits **/
  453.  
  454. static int my_mkdir(const char* path, int p)
  455. {
  456.     if(checkusergrouplib()) p &= ~getumask();
  457.     else err_clear();
  458.  
  459.     if(0==mkdir(path))
  460.     {
  461.         return chmod(path,p);
  462.     }
  463.     return -1;
  464. }
  465.  
  466. static object *
  467. amiga_mkdir(object *self, object *args)
  468. {
  469.     int res;
  470.     char *path;
  471.     int mode = 0777;
  472.     if (!newgetargs(args, "s|i", &path, &mode))    return NULL;
  473.     BGN_SAVE
  474.     res = my_mkdir(path, mode);
  475.     END_SAVE
  476.     if (res < 0) return amiga_error();
  477.     INCREF(None); return None;
  478. }
  479.  
  480. static object *
  481. amiga_rename(object *self, object *args)
  482. {
  483.     return amiga_2str(args, rename);
  484. }
  485.  
  486. static object *
  487. amiga_rmdir(object *self, object *args)
  488. {
  489.     return amiga_1str(args, rmdir);
  490. }
  491.  
  492. static object *
  493. amiga_stat(object *self, object *args)
  494. {
  495.     return amiga_do_stat(self, args, stat);
  496. }
  497.  
  498. static object *
  499. amiga_system(object *self, object *args)
  500. {
  501.     char *command;
  502.     long sts;
  503.     if (!getargs(args, "s", &command))
  504.         return NULL;
  505.     BGN_SAVE
  506.     sts = system(command);
  507.     END_SAVE
  508.     return newintobject(sts);
  509. }
  510.  
  511. #ifdef AMITCP
  512. static object *
  513. amiga_umask(object *self, object *args)
  514. {
  515.     int i;
  516.     if (!checkusergrouplib()) return NULL;
  517.     if (!getintarg(args, &i))
  518.         return NULL;
  519.     i = umask(i);
  520.     if (i < 0)
  521.         return amiga_error();
  522.     return newintobject((long)i);
  523. }
  524. #endif
  525.  
  526. #define _UNAME_BUFLEN 32
  527. struct _utsname {
  528.         char    sysname[_UNAME_BUFLEN];
  529.         char    nodename[_UNAME_BUFLEN];
  530.         char    release[_UNAME_BUFLEN];
  531.         char    version[_UNAME_BUFLEN];
  532.         char    machine[_UNAME_BUFLEN];
  533. };
  534.  
  535. static object *
  536. amiga_uname(object *self, object *args)
  537. {
  538.         struct _utsname u;
  539.         object *v;
  540.         int res;
  541.         if (!getnoarg(args))
  542.                 return NULL;
  543.         strcpy(u.sysname,"AmigaDOS");
  544.         strcpy(u.version,"1");
  545.         strcpy(u.machine,"m68k");
  546.         BGN_SAVE
  547.         if (!checkbsdsocketlib())
  548.         {
  549.             char *v;
  550.             err_clear();
  551.             res=0; v=getenv("HOSTNAME");
  552.             if(v) strcpy(u.nodename, v);
  553.             else strcpy(u.nodename, "localhost");
  554.         }
  555.         else res = gethostname(u.nodename, _UNAME_BUFLEN-1);
  556.         if(res>=0)
  557.         {
  558.             LONG ver_major = SysBase->LibNode.lib_Version;
  559.             LONG ver_minor = SysBase->SoftVer;
  560.             sprintf (u.release, "%d.%d", ver_major,ver_minor);
  561.             if(ver_major<36)
  562.                 strcpy(u.version,"1");
  563.             else if(ver_major<39)
  564.                 strcpy(u.version,"2");
  565.             else 
  566.                 strcpy(u.version,"3");
  567.         }
  568.         END_SAVE
  569.         if (res < 0)
  570.                 return amiga_error();
  571.         return mkvalue("(sssss)",
  572.                        u.sysname,
  573.                        u.nodename,
  574.                        u.release,
  575.                        u.version,
  576.                        u.machine);
  577. }
  578.  
  579. static object *
  580. amiga_unlink(object *self, object *args)
  581. {
  582.     return amiga_1str(args, unlink);
  583. }
  584.  
  585. #ifdef AMITCP
  586. static object *
  587. amiga_utime(object *self, object *args)
  588. {
  589.     char *path;
  590.     long atime, mtime;
  591.     int res;
  592.  
  593. #ifdef HAVE_UTIME_H
  594.     struct utimbuf buf;
  595. #define ATIME buf.actime
  596. #define MTIME buf.modtime
  597. #define UTIME_ARG &buf
  598. #else /* HAVE_UTIME_H */
  599.     time_t buf[2];
  600. #define ATIME buf[0]
  601. #define MTIME buf[1]
  602. #define UTIME_ARG buf
  603. #endif /* HAVE_UTIME_H */
  604.  
  605.     if (!getargs(args, "(s(ll))", &path, &atime, &mtime))
  606.         return NULL;
  607.     ATIME = atime;
  608.     MTIME = mtime;
  609.     BGN_SAVE
  610.     res = utime(path, UTIME_ARG);
  611.     END_SAVE
  612.     if (res < 0)
  613.         return amiga_error();
  614.     INCREF(None);
  615.     return None;
  616. #undef UTIME_ARG
  617. #undef ATIME
  618. #undef MTIME
  619. }
  620. #endif
  621.  
  622.  
  623. /* Process operations */
  624.  
  625. /* XXX Removed _exit. You are VERY STUPID if you used this. (2-apr-96) */
  626.  
  627. /* XXX Removed execv. You must use system/exit combination instead. */
  628. /*     Maybe one day I'll implement a REAL execv ?? */
  629.  
  630.  
  631.  
  632. #ifdef HAVE_GETEGID
  633. static object *
  634. amiga_getegid(object *self, object *args)
  635. {
  636.     if (!checkusergrouplib()) return NULL;
  637.     if (!getnoarg(args))
  638.         return NULL;
  639.     return newintobject((long)getegid());
  640. }
  641. #endif
  642.  
  643. #ifdef HAVE_GETEUID
  644. static object *
  645. amiga_geteuid(object *self, object *args)
  646. {
  647.     if (!checkusergrouplib()) return NULL;
  648.     if (!getnoarg(args))
  649.         return NULL;
  650.     return newintobject((long)geteuid());
  651. }
  652. #endif
  653.  
  654. #ifdef HAVE_GETGID
  655. static object *
  656. amiga_getgid(object *self, object *args)
  657. {
  658.     if (!checkusergrouplib()) return NULL;
  659.     if (!getnoarg(args))
  660.         return NULL;
  661.     return newintobject((long)getgid());
  662. }
  663. #endif
  664.  
  665. static object *
  666. amiga_getpid(object *self, object *args)
  667. {
  668.     if (!getnoarg(args))
  669.         return NULL;
  670.     return newintobject((long)FindTask(0));
  671. }
  672.  
  673. #ifdef HAVE_GETPGRP
  674. static object *
  675. amiga_getpgrp(object *self, object *args)
  676. {
  677.     if (!checkusergrouplib()) return NULL;
  678.     if (!getnoarg(args))
  679.         return NULL;
  680. #ifdef GETPGRP_HAVE_ARG
  681.     return newintobject((long)getpgrp(0));
  682. #else /* GETPGRP_HAVE_ARG */
  683.     return newintobject((long)getpgrp());
  684. #endif /* GETPGRP_HAVE_ARG */
  685. }
  686. #endif /* HAVE_GETPGRP */
  687.  
  688. #ifdef HAVE_SETPGRP
  689. static object *
  690. amiga_setpgrp(object *self, object *args)
  691. {
  692.     if (!checkusergrouplib()) return NULL;
  693.     if (!getnoarg(args))
  694.         return NULL;
  695. #ifdef SETPGRP_HAVE_ARG
  696.     if (setpgrp(0, 0) < 0)
  697. #else /* SETPGRP_HAVE_ARG */
  698.     if (setpgrp() < 0)
  699. #endif /* SETPGRP_HAVE_ARG */
  700.         return amiga_error();
  701.     INCREF(None);
  702.     return None;
  703. }
  704.  
  705. #endif /* HAVE_SETPGRP */
  706.  
  707. #ifdef HAVE_GETPPID
  708. static object *
  709. amiga_getppid(object *self, object *args)
  710. {
  711.     if (!getnoarg(args))
  712.         return NULL;
  713.     return newintobject((long)getppid());
  714. }
  715. #endif
  716.  
  717. #ifdef HAVE_GETUID
  718. static object *
  719. amiga_getuid(object *self, object *args)
  720. {
  721.     if (!checkusergrouplib()) return NULL;
  722.     if (!getnoarg(args))
  723.         return NULL;
  724.     return newintobject((long)getuid());
  725. }
  726. #endif
  727.  
  728. FILE *popen(const char *command, const char *type)
  729. {
  730.     char file[50];
  731.  
  732.     FILE *fh;
  733.  
  734.     static int num = 1;
  735.  
  736.     if((type[0]!='r') && (type[0]!='w'))
  737.     {
  738.         errno=EINVAL;
  739.         return 0;
  740.     }
  741.         
  742.     sprintf(file,"PIPE:Py_%ld_%ld",num++,FindTask(0));
  743.  
  744.     if(fh=fopen(file,type))
  745.     {
  746.         BPTR fh2;
  747.         LONG mode;
  748.  
  749.         if(type[0]=='r') mode=MODE_NEWFILE;
  750.         if(type[0]=='w') mode=MODE_OLDFILE;
  751.         if(fh2=Open(file,mode))
  752.         {
  753.             BPTR fh3;
  754.             if(type[0]=='r')
  755.             {
  756.                 /* execute command with output to fh */
  757.                 fh3=Open("*",MODE_OLDFILE); /* should use CONSOLE: */
  758.                 if(fh3 && (0==SystemTags(command,SYS_Asynch,TRUE,SYS_Output,fh2,
  759.                                     SYS_Input,fh3,TAG_DONE)))
  760.                 {
  761.                     return fh;
  762.                 }
  763.             }
  764.             else /** if(type[0]=='w') **/
  765.             {
  766.                 /* execute command with input from fh */
  767.                 fh3=Open("*",MODE_NEWFILE); /* should use CONSOLE: */
  768.                 if(fh3 && (0==SystemTags(command,SYS_Asynch,TRUE,SYS_Input,fh2,
  769.                                     SYS_Output,fh3,TAG_DONE)))
  770.                 {
  771.                     return fh;
  772.                 }
  773.             }
  774.             fclose(fh); Close(fh2); if(fh3) Close(fh3);
  775.             errno=EAGAIN;
  776.             return 0;
  777.         }
  778.         fclose(fh);
  779.     }
  780.     errno=ENOENT;
  781.     return 0;
  782. }
  783.  
  784. int pclose(FILE *stream)
  785. {
  786.     if(stream)
  787.     {
  788.         fclose(stream);
  789.         return 0;
  790.     }
  791.     errno=EINVAL;
  792.     return -1;  
  793. }
  794.  
  795. static object *
  796. amiga_popen(object *self, object *args)
  797. {
  798.     char *name;
  799.     char *mode = "r";
  800.     int bufsize = -1;
  801.     FILE *fp;
  802.     object *f;
  803.     if (!newgetargs(args, "s|si", &name, &mode, &bufsize))
  804.         return NULL;
  805.     BGN_SAVE
  806.     fp = popen(name, mode);
  807.     END_SAVE
  808.     if (fp == NULL)
  809.         return amiga_error();
  810.     f = newopenfileobject(fp, name, mode, pclose);
  811.     if (f != NULL)
  812.         setfilebufsize(f, bufsize);
  813.     return f;
  814. }
  815.  
  816. #ifdef HAVE_SETUID
  817. static object *
  818. amiga_setuid(object *self, object *args)
  819. {
  820.     int uid;
  821.     if (!checkusergrouplib()) return NULL;
  822.     if (!getargs(args, "i", &uid))
  823.         return NULL;
  824.     if (setuid(uid) < 0)
  825.         return amiga_error();
  826.     INCREF(None);
  827.     return None;
  828. }
  829. #endif /* HAVE_SETUID */
  830.  
  831. #ifdef HAVE_SETGID
  832. static object *
  833. amiga_setgid(object *self, object *args)
  834. {
  835.     int gid;
  836.     if (!checkusergrouplib()) return NULL;
  837.     if (!getargs(args, "i", &gid))
  838.         return NULL;
  839.     if (setgid(gid) < 0)
  840.         return amiga_error();
  841.     INCREF(None);
  842.     return None;
  843. }
  844. #endif /* HAVE_SETGID */
  845.  
  846. static object *
  847. amiga_lstat(object *self, object *args)
  848. {
  849. #ifdef HAVE_LSTAT
  850.     return amiga_do_stat(self, args, lstat);
  851. #else /* !HAVE_LSTAT */
  852.     return amiga_do_stat(self, args, stat);
  853. #endif /* !HAVE_LSTAT */
  854. }
  855.  
  856. static object *
  857. amiga_readlink(object *self, object *args)
  858. {
  859.     char buf[MAXPATHLEN];
  860.     char *path;
  861.     struct MsgPort *port;
  862.     struct stat st;
  863.  
  864.     if (!getargs(args, "s", &path)) return NULL;
  865.  
  866.     if(!(port=DeviceProc(path)))
  867.     {
  868.         err_setstr(IOError,"no deviceproc"); return NULL;
  869.     }
  870.  
  871.     errno=0;
  872.  
  873.     BGN_SAVE
  874.     if(lstat(path,&st)>=0)
  875.     {
  876.         if(S_ISLNK(st.st_mode))
  877.         {
  878.             char c;
  879.             BPTR dirlock;
  880.             BPTR olddir;
  881.             char *p;
  882.             char *link;
  883.  
  884.             p = PathPart(path);
  885.             link = FilePart(path);
  886.             c = *p;    *p='\0';
  887.             dirlock=Lock(path,ACCESS_READ); *p=c;
  888.             if(dirlock)
  889.             {
  890.                 olddir=CurrentDir(dirlock);
  891.  
  892.                 if(!ReadLink(port,dirlock,link,buf,sizeof(buf)))
  893.                     errno=__io2errno(_OSERR=IoErr());
  894.  
  895.                 dirlock=CurrentDir(olddir);
  896.                 UnLock(dirlock);
  897.             }    
  898.             else errno=__io2errno(_OSERR=IoErr());
  899.         }
  900.         else errno=EINVAL;
  901.     }
  902.  
  903.     END_SAVE
  904.     if(errno!=0) return amiga_error();
  905.     else return newstringobject(buf);
  906. }
  907.  
  908. /** Amiga implementation of symlink(2) (12-Apr-96) **/
  909. static int symlink(const char *to, const char *from)
  910. {
  911.     /* symbolic link 'from' is created to 'to' */
  912.     /* 0=ok, else -1 + errno */
  913.  
  914.     BPTR toLock;
  915.  
  916.     if(toLock=Lock(to,SHARED_LOCK))
  917.     {
  918.         if(checkIt(from,toLock,TRUE))
  919.         {
  920.             UnLock(toLock);
  921.             if(MakeLink(from,(LONG)to,TRUE)) return 0;
  922.             else errno=__io2errno(_OSERR=IoErr());
  923.         }
  924.         else UnLock(toLock);
  925.     }
  926.     else errno=__io2errno(_OSERR=IoErr());
  927.     
  928.     return -1;
  929. }
  930.  
  931. static object *
  932. amiga_symlink(object *self, object *args)
  933. {
  934.     return amiga_2str(args, symlink);
  935. }
  936.  
  937. #ifdef HAVE_SETSID
  938. static object *
  939. amiga_setsid(object *self, object *args)
  940. {
  941.     if (!checkusergrouplib()) return NULL;
  942.     if (!getnoarg(args))
  943.         return NULL;
  944.     if ((int)setsid() < 0)
  945.         return amiga_error();
  946.     INCREF(None);
  947.     return None;
  948. }
  949. #endif /* HAVE_SETSID */
  950.  
  951. #ifdef HAVE_SETPGID
  952. static object *
  953. amiga_setpgid(object *self, object *args)
  954. {
  955.     int pid, pgrp;
  956.     if (!getargs(args, "(ii)", &pid, &pgrp))
  957.         return NULL;
  958.     if (setpgid(pid, pgrp) < 0)
  959.         return amiga_error();
  960.     INCREF(None);
  961.     return None;
  962. }
  963. #endif /* HAVE_SETPGID */
  964.  
  965. /* Functions acting on file descriptors */
  966.  
  967. static object *
  968. amiga_open(object *self, object *args)
  969. {
  970.     char *file;
  971.     int flag;
  972.     int mode = 0777;
  973.     int fd;
  974.     if (!getargs(args, "(si)", &file, &flag)) {
  975.         err_clear();
  976.         if (!getargs(args, "(sii)", &file, &flag, &mode))
  977.             return NULL;
  978.     }
  979.     BGN_SAVE
  980.     fd = open(file, flag, mode);
  981.     END_SAVE
  982.     if (fd < 0)
  983.         return amiga_error();
  984.     return newintobject((long)fd);
  985. }
  986.  
  987. static object *
  988. amiga_close(object *self, object *args)
  989. {
  990.     int fd, res;
  991.     if (!getargs(args, "i", &fd))
  992.         return NULL;
  993.     BGN_SAVE
  994.     res = close(fd);
  995.     END_SAVE
  996.     if (res < 0)
  997.         return amiga_error();
  998.     INCREF(None);
  999.     return None;
  1000. }
  1001.  
  1002. #ifdef AMITCP
  1003. static object *
  1004. amiga_dup(object *self, object *args)
  1005. {
  1006.     int fd;
  1007.     if (!checkbsdsocketlib()) { err_clear(); errno=EIO; return amiga_error(); }
  1008.     if (!getargs(args, "i", &fd))
  1009.         return NULL;
  1010.     BGN_SAVE
  1011.     fd = dup(fd);
  1012.     END_SAVE
  1013.     if (fd < 0)
  1014.         return amiga_error();
  1015.     return newintobject((long)fd);
  1016. }
  1017.  
  1018. static object *
  1019. amiga_dup2(object *self, object *args)
  1020. {
  1021.     int fd, fd2, res;
  1022.     if (!checkbsdsocketlib()) { err_clear(); errno=EIO; return amiga_error(); }
  1023.     if (!getargs(args, "(ii)", &fd, &fd2))
  1024.         return NULL;
  1025.     BGN_SAVE
  1026.     res = dup2(fd, fd2);
  1027.     END_SAVE
  1028.     if (res < 0)
  1029.         return amiga_error();
  1030.     INCREF(None);
  1031.     return None;
  1032. }
  1033. #endif
  1034.  
  1035. static object *
  1036. amiga_lseek(object *self, object *args)
  1037. {
  1038.     int fd, how;
  1039.     long pos, res;
  1040.     if (!getargs(args, "(ili)", &fd, &pos, &how))
  1041.         return NULL;
  1042. #ifdef SEEK_SET
  1043.     /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
  1044.     switch (how) {
  1045.     case 0: how = SEEK_SET; break;
  1046.     case 1: how = SEEK_CUR; break;
  1047.     case 2: how = SEEK_END; break;
  1048.     }
  1049. #endif /* SEEK_END */
  1050.     BGN_SAVE
  1051.     res = lseek(fd, pos, how);
  1052.     END_SAVE
  1053.     if (res < 0)
  1054.         return amiga_error();
  1055.     return newintobject(res);
  1056. }
  1057.  
  1058. static object *
  1059. amiga_read(object *self, object *args)
  1060. {
  1061.     int fd, size;
  1062.     object *buffer;
  1063.     if (!getargs(args, "(ii)", &fd, &size))
  1064.         return NULL;
  1065.     buffer = newsizedstringobject((char *)NULL, size);
  1066.     if (buffer == NULL)
  1067.         return NULL;
  1068.     BGN_SAVE
  1069.     size = read(fd, getstringvalue(buffer), size);
  1070.     END_SAVE
  1071.     if (size < 0) {
  1072.         DECREF(buffer);
  1073.         return amiga_error();
  1074.     }
  1075.     resizestring(&buffer, size);
  1076.     return buffer;
  1077. }
  1078.  
  1079. static object *
  1080. amiga_write(object *self, object *args)
  1081. {
  1082.     int fd, size;
  1083.     char *buffer;
  1084.     if (!getargs(args, "(is#)", &fd, &buffer, &size))
  1085.         return NULL;
  1086.     BGN_SAVE
  1087.     size = write(fd, buffer, size);
  1088.     END_SAVE
  1089.     if (size < 0)
  1090.         return amiga_error();
  1091.     return newintobject((long)size);
  1092. }
  1093.  
  1094. static object *
  1095. amiga_fstat(object *self, object *args)
  1096. {
  1097.     int fd;
  1098.     struct stat st;
  1099.     int res;
  1100.     if (!getargs(args, "i", &fd))
  1101.         return NULL;
  1102.     BGN_SAVE
  1103.     res = fstat(fd, &st);
  1104.     END_SAVE
  1105.     if (res != 0)
  1106.         return amiga_error();
  1107.     return mkvalue("(llllllllll)",
  1108.             (long)st.st_mode,
  1109.             (long)st.st_ino,
  1110.             (long)st.st_dev,
  1111.             (long)st.st_nlink,
  1112.             (long)st.st_uid,
  1113.             (long)st.st_gid,
  1114.             (long)st.st_size,
  1115.             (long)st.st_atime,
  1116.             (long)st.st_mtime,
  1117.             (long)st.st_ctime);
  1118. }
  1119.  
  1120. static object *
  1121. amiga_fdopen(object *self, object *args)
  1122. {
  1123.     int fd;
  1124.     char *mode = "r";
  1125.     int bufsize = -1;
  1126.     FILE *fp;
  1127.     object *f;
  1128.     if (!newgetargs(args, "i|si", &fd, &mode, &bufsize))
  1129.         return NULL;
  1130.     BGN_SAVE
  1131.     fp = fdopen(fd, mode);
  1132.     END_SAVE
  1133.     if (fp == NULL)
  1134.         return amiga_error();
  1135.     f = newopenfileobject(fp, "(fdopen)", mode, fclose);
  1136.     if (f != NULL)
  1137.         setfilebufsize(f, bufsize);
  1138.     return f;
  1139. }
  1140.  
  1141. #if 0
  1142. /*** XXX pipe() is useless without fork() or threads ***/
  1143. /***     TODO: guess what.. implement threads! ***/
  1144. static int pipe(int *fildes)
  1145. {
  1146.     /* 0=ok, -1=err, errno=EMFILE,ENFILE,EFAULT */
  1147.     char buf[50];
  1148.     static int num = 1;
  1149.     
  1150.     sprintf(buf,"PIPE:Py%ld_%ld",FindTask(0),num++);
  1151.     fildes[0]=open(buf,O_RDONLY,0);
  1152.     if(fildes[0]>0)
  1153.     {
  1154.         fildes[1]=open(buf,O_WRONLY|O_CREAT,FIBF_OTR_READ|FIBF_OTR_WRITE);
  1155.         if(fildes[1]>0)
  1156.         {
  1157.             return 0;
  1158.         }
  1159.         close(fildes[0]);
  1160.     }
  1161.     return -1;
  1162. }
  1163.  
  1164. static object *
  1165. amiga_pipe(object *self, object *args)
  1166. {
  1167.     int fds[2];
  1168.     int res;
  1169.     if (!getargs(args, ""))
  1170.         return NULL;
  1171.     BGN_SAVE
  1172.     res = pipe(fds);
  1173.     END_SAVE
  1174.     if (res != 0)
  1175.         return amiga_error();
  1176.     return mkvalue("(ii)", fds[0], fds[1]);
  1177. }
  1178. #endif
  1179.  
  1180.  
  1181. static object *
  1182. amiga_fullpath(object *self, object *args)
  1183. {
  1184.     BOOL ok=FALSE;
  1185.     BPTR lk;
  1186.     char *path;
  1187.     char buf[MAXPATHLEN];
  1188.  
  1189.     if (!newgetargs(args, "s", &path)) return NULL;
  1190.  
  1191.     BGN_SAVE
  1192.     if(lk=Lock(path,SHARED_LOCK))
  1193.     {
  1194.         ok=NameFromLock(lk,buf,sizeof(buf));
  1195.         UnLock(lk);
  1196.     }
  1197.     END_SAVE
  1198.  
  1199.     if(!ok)
  1200.     {
  1201.         errno=__io2errno(_OSERR=IoErr());
  1202.         return amiga_error();
  1203.     }
  1204.     else return newstringobject(buf);
  1205. }
  1206.  
  1207. static object *amiga_putenv(object *self, object *args)
  1208. {
  1209.     char *s1, *s2;
  1210.  
  1211.     if (!newgetargs(args, "ss", &s1, &s2)) return NULL;
  1212.     if(setenv(s1,s2,1))
  1213.     {
  1214.         amiga_error(); return NULL;
  1215.     }
  1216.     
  1217.     INCREF(None); return None;
  1218. }
  1219.  
  1220. static struct methodlist amiga_methods[] = {
  1221.     {"chdir",   amiga_chdir},
  1222.     {"chmod",   amiga_chmod},
  1223. #ifdef HAVE_CHOWN
  1224.     {"chown",   amiga_chown},
  1225. #endif
  1226. #ifdef HAVE_GETCWD
  1227.     {"getcwd",  amiga_getcwd},
  1228. #endif
  1229.     {"fullpath", amiga_fullpath,1},
  1230.     {"link",    amiga_link},
  1231.     {"listdir", amiga_listdir},
  1232.     {"lstat",   amiga_lstat},
  1233.     {"mkdir",   amiga_mkdir , 1},
  1234.     {"readlink",    amiga_readlink},
  1235.     {"rename",  amiga_rename},
  1236.     {"rmdir",   amiga_rmdir},
  1237.     {"stat",    amiga_stat},
  1238.     {"symlink", amiga_symlink},
  1239.     {"system",  amiga_system},
  1240. #ifdef AMITCP
  1241.     {"umask",   amiga_umask},
  1242. #endif
  1243.     {"uname",   amiga_uname},
  1244.     {"unlink",  amiga_unlink},
  1245.     {"remove",  amiga_unlink},
  1246. #ifdef AMITCP
  1247.     {"utime",   amiga_utime},
  1248. #endif
  1249. #ifdef HAVE_TIMES
  1250.     {"times",   amiga_times},
  1251. #endif
  1252. #ifdef HAVE_GETEGID
  1253.     {"getegid", amiga_getegid},
  1254. #endif
  1255. #ifdef HAVE_GETEUID
  1256.     {"geteuid", amiga_geteuid},
  1257. #endif
  1258. #ifdef HAVE_GETGID
  1259.     {"getgid",  amiga_getgid},
  1260. #endif
  1261.     {"getpid",  amiga_getpid},
  1262. #ifdef HAVE_GETPGRP
  1263.     {"getpgrp", amiga_getpgrp},
  1264. #endif
  1265. #ifdef HAVE_GETPPID
  1266.     {"getppid", amiga_getppid},
  1267. #endif
  1268. #ifdef HAVE_GETUID
  1269.     {"getuid",  amiga_getuid},
  1270. #endif
  1271.     {"popen",   amiga_popen,    1},
  1272. #ifdef HAVE_SETUID
  1273.     {"setuid",  amiga_setuid},
  1274. #endif
  1275. #ifdef HAVE_SETGID
  1276.     {"setgid",  amiga_setgid},
  1277. #endif
  1278. #ifdef HAVE_SETPGRP
  1279.     {"setpgrp", amiga_setpgrp},
  1280. #endif
  1281. #ifdef HAVE_SETSID
  1282.     {"setsid",  amiga_setsid},
  1283. #endif
  1284. #ifdef HAVE_SETPGID
  1285.     {"setpgid", amiga_setpgid},
  1286. #endif
  1287. #ifdef HAVE_TCGETPGRP
  1288.     {"tcgetpgrp",   amiga_tcgetpgrp},
  1289. #endif
  1290. #ifdef HAVE_TCSETPGRP
  1291.     {"tcsetpgrp",   amiga_tcsetpgrp},
  1292. #endif
  1293.     {"open",    amiga_open},
  1294.     {"close",   amiga_close},
  1295. #ifdef AMITCP
  1296.     {"dup",     amiga_dup},
  1297.     {"dup2",    amiga_dup2},
  1298. #endif
  1299.     {"lseek",   amiga_lseek},
  1300.     {"read",    amiga_read},
  1301.     {"write",   amiga_write},
  1302.     {"fstat",   amiga_fstat},
  1303.     {"fdopen",  amiga_fdopen,   1},
  1304.     {"putenv",    amiga_putenv, 1},
  1305. #if 0
  1306.     /* XXX TODO: implement threads. Otherwise pipe() is useless. */
  1307.     {"pipe",    amiga_pipe},
  1308. #endif
  1309.     {NULL,      NULL}        /* Sentinel */
  1310. };
  1311.  
  1312.  
  1313. void
  1314. initamiga(void)
  1315. {
  1316.     object *m, *d, *globv, *locv, *bothv, *aliases;
  1317.  
  1318.     m = initmodule("amiga", amiga_methods);
  1319.     d = getmoduledict(m);
  1320.     
  1321.     /* Initialize amiga.environ dictionary */
  1322.     if(!convertenviron(&globv, &locv, &bothv, &aliases))
  1323.         fatal("can't read environment");
  1324.  
  1325.     if (dictinsert(d, "environ", bothv) != 0)
  1326.         fatal("can't define amiga.environ");
  1327.     DECREF(bothv);
  1328.     if (dictinsert(d, "globalvars", globv) != 0)
  1329.         fatal("can't define amiga.globalvars");
  1330.     DECREF(globv);
  1331.     if (dictinsert(d, "shellvars", locv) != 0)
  1332.         fatal("can't define amiga.shellvars");
  1333.     DECREF(locv);
  1334.     if (dictinsert(d, "shellaliases", aliases ) != 0)
  1335.         fatal("can't define amiga.shellaliases");
  1336.     DECREF(aliases);
  1337.  
  1338.     /* Initialize amiga.error exception */
  1339.     AmigaError = newstringobject("amiga.error");
  1340.     if (AmigaError == NULL || dictinsert(d, "error", AmigaError) != 0)
  1341.         fatal("can't define amiga.error");
  1342. }
  1343.